#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import subprocess
import json
import re
from pathlib import Path


class VideoInfo:
    """视频信息类"""
    def __init__(self, file_path):
        self.file_path = file_path
        self.duration = 0
        self.width = 0
        self.height = 0
        self.fps = 0
        self.bitrate = 0
        self.codec = ''
        self.audio_codec = ''
        self.format_name = ''
        
    def load_info(self):
        """加载视频信息"""
        try:
            # 优先使用当前脚本所在目录下的ffmpeg
            import platform
            script_dir = os.path.dirname(os.path.abspath(__file__))
            
            # 根据操作系统选择正确的可执行文件名
            if platform.system() == 'Windows':
                ffmpeg_name = 'ffmpeg.exe'
            else:
                ffmpeg_name = 'ffmpeg'
            
            local_ffmpeg = os.path.join(script_dir, ffmpeg_name)
            
            if os.path.exists(local_ffmpeg):
                ffmpeg_cmd = local_ffmpeg
            else:
                ffmpeg_cmd = 'ffmpeg'
            
            # 使用ffmpeg -i 来获取视频信息
            cmd = [
                ffmpeg_cmd,
                '-i', self.file_path,
                '-f', 'null',
                '-'
            ]
            
            result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8')
            
            # ffmpeg输出信息在stderr中
            output = result.stderr
            
            if not output:
                print(f"FFmpeg error: 无法获取视频信息")
                return False
            
            # 解析输出信息
            lines = output.split('\n')
            
            # 查找Duration行
            for line in lines:
                if 'Duration:' in line:
                    # 解析时长 Duration: 00:00:10.00, start: 0.000000, bitrate: 200 kb/s
                    duration_match = re.search(r'Duration: (\d+):(\d+):(\d+\.\d+)', line)
                    if duration_match:
                        hours = int(duration_match.group(1))
                        minutes = int(duration_match.group(2))
                        seconds = float(duration_match.group(3))
                        self.duration = hours * 3600 + minutes * 60 + seconds
                    
                    # 解析比特率
                    bitrate_match = re.search(r'bitrate: (\d+) kb/s', line)
                    if bitrate_match:
                        self.bitrate = int(bitrate_match.group(1)) * 1000
                
                # 查找视频流信息
                elif 'Stream #' in line and 'Video:' in line:
                    # 解析视频流 Stream #0:0(und): Video: wrapped_avframe, yuv444p(progressive), 320x240 [SAR 1:1 DAR 4:3], q=2-31, 200 kb/s, 1 fps, 1 tbn (default)
                    # 解析编码器
                     codec_match = re.search(r'Video: ([^,]+)', line)
                     if codec_match:
                         self.video_codec = codec_match.group(1).strip()
                     
                     # 解析分辨率
                     resolution_match = re.search(r'(\d+)x(\d+)', line)
                     if resolution_match:
                         self.width = int(resolution_match.group(1))
                         self.height = int(resolution_match.group(2))
                     
                     # 解析帧率
                     fps_match = re.search(r'(\d+(?:\.\d+)?) fps', line)
                     if fps_match:
                         self.fps = float(fps_match.group(1))
                
                # 查找音频流信息
                elif 'Stream #' in line and 'Audio:' in line:
                    # 解析音频编码器
                    codec_match = re.search(r'Audio: ([^,]+)', line)
                    if codec_match:
                        self.audio_codec = codec_match.group(1).strip()
            
            # 设置默认格式名称
            if not self.format_name:
                ext = os.path.splitext(self.file_path)[1].lower()
                if ext == '.mp4':
                    self.format_name = 'mp4'
                elif ext == '.avi':
                    self.format_name = 'avi'
                elif ext == '.mov':
                    self.format_name = 'mov'
                else:
                    self.format_name = ext[1:] if ext else 'unknown'
            
            return True
            
        except Exception as e:
            print(f"Error loading video info: {e}")
            return False
    
    def get_resolution_string(self):
        """获取分辨率字符串"""
        return f"{self.width}x{self.height}"
    
    def get_duration_string(self):
        """获取时长字符串"""
        hours = int(self.duration // 3600)
        minutes = int((self.duration % 3600) // 60)
        seconds = int(self.duration % 60)
        return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
    
    def is_valid(self):
        """检查视频信息是否有效"""
        return self.load_info() and self.duration > 0
    
    def get_file_size_string(self):
        """获取文件大小字符串"""
        try:
            size_bytes = os.path.getsize(self.file_path)
            return format_file_size(size_bytes)
        except OSError:
            return "未知大小"


class VideoSplitter:
    """视频拆分器"""
    
    SUPPORTED_FORMATS = {
        'mp4': 'MP4 Video',
        'avi': 'AVI Video', 
        'mov': 'QuickTime Movie',
        'mkv': 'Matroska Video',
        'wmv': 'Windows Media Video',
        '3gp': '3GPP Video'
    }
    
    RESOLUTION_PRESETS = {
        '1080p': (1920, 1080),
        '720p': (1280, 720),
        '480p': (854, 480),
        '360p': (640, 360)
    }
    
    def __init__(self):
        self.ffmpeg_available = self.check_ffmpeg()
    
    def get_ffmpeg_executable_names(self):
        """根据操作系统返回正确的FFmpeg可执行文件名"""
        import platform
        if platform.system() == 'Windows':
            return 'ffmpeg.exe', 'ffprobe.exe'
        else:
            return 'ffmpeg', 'ffprobe'
    
    def check_ffmpeg(self):
        """检查FFmpeg是否可用"""
        # 优先检查本地FFmpeg
        current_dir = Path(__file__).parent
        ffmpeg_name, ffprobe_name = self.get_ffmpeg_executable_names()
        
        local_ffmpeg = current_dir / ffmpeg_name
        local_ffprobe = current_dir / ffprobe_name
        
        if local_ffmpeg.exists() and local_ffprobe.exists():
            return True
        
        # 检查系统FFmpeg
        try:
            result = subprocess.run(['ffmpeg', '-version'], 
                                  capture_output=True, text=True)
            return result.returncode == 0
        except FileNotFoundError:
            return False
    
    def is_supported_format(self, file_path):
        """检查是否为支持的视频格式"""
        ext = Path(file_path).suffix.lower().lstrip('.')
        return ext in self.SUPPORTED_FORMATS
    
    def get_format_filter(self):
        """获取文件格式过滤器"""
        extensions = [f'*.{ext}' for ext in self.SUPPORTED_FORMATS.keys()]
        return extensions
    
    def build_split_command(self, input_file, output_file, start_time, duration, 
                          resolution=None, quality='medium'):
        """构建拆分命令"""
        # 优先使用本地ffmpeg
        current_dir = Path(__file__).parent
        ffmpeg_name, _ = self.get_ffmpeg_executable_names()
        local_ffmpeg = current_dir / ffmpeg_name
        
        if local_ffmpeg.exists():
            ffmpeg_cmd = str(local_ffmpeg)
        else:
            ffmpeg_cmd = 'ffmpeg'  # 使用系统PATH中的ffmpeg
        
        cmd = [
            ffmpeg_cmd, '-y',  # 覆盖输出文件
            '-ss', str(start_time),  # 开始时间
            '-i', input_file,  # 输入文件
            '-t', str(duration),  # 持续时间
        ]
        
        # 视频编码设置 - 强制使用高质量设置以保持1080P质量
        cmd.extend(['-c:v', 'libx264', '-crf', '18'])  # 高质量编码
        
        # 音频编码设置 - 提高音频质量
        cmd.extend(['-c:a', 'aac', '-b:a', '192k'])
        
        # 强制设置为1080P分辨率和30fps
        cmd.extend(['-vf', 'scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2'])
        cmd.extend(['-r', '30'])  # 设置帧率为30fps
        
        # 其他设置
        cmd.extend([
            '-movflags', '+faststart',  # 优化网络播放
            '-preset', 'medium',  # 编码速度预设
            '-pix_fmt', 'yuv420p',  # 确保兼容性
            output_file
        ])
        
        return cmd
    
    def split_video(self, input_file, split_points, output_dir, 
                   resolution=None, quality='medium', progress_callback=None):
        """拆分视频"""
        if not self.ffmpeg_available:
            raise Exception("FFmpeg not available")
        
        if not os.path.exists(input_file):
            raise Exception(f"Input file not found: {input_file}")
        
        # 创建输出目录
        os.makedirs(output_dir, exist_ok=True)
        
        # 获取视频信息
        video_info = VideoInfo(input_file)
        if not video_info.load_info():
            raise Exception("Failed to load video information")
        
        # 准备拆分时间点
        times = [0] + sorted(split_points) + [video_info.duration]
        segments = []
        
        # 获取源视频文件名（不含扩展名）
        input_filename = os.path.splitext(os.path.basename(input_file))[0]
        
        for i in range(len(times) - 1):
            start_time = times[i]
            end_time = times[i + 1]
            duration = end_time - start_time
            
            if duration <= 0:
                continue
            
            # 使用源视频文件名_序号的命名方式
            output_file = os.path.join(output_dir, f"{input_filename}_{i+1}.mp4")
            
            segment_info = {
                'index': i + 1,
                'start_time': start_time,
                'duration': duration,
                'output_file': output_file
            }
            segments.append(segment_info)
        
        # 执行拆分
        total_segments = len(segments)
        successful_segments = []
        
        for i, segment in enumerate(segments):
            if progress_callback:
                progress_callback(i, total_segments, f"Processing segment {i+1}/{total_segments}")
            
            cmd = self.build_split_command(
                input_file, segment['output_file'],
                segment['start_time'], segment['duration'],
                resolution, quality
            )
            
            try:
                result = subprocess.run(cmd, capture_output=True, text=True)
                
                if result.returncode == 0:
                    successful_segments.append(segment)
                else:
                    print(f"Error processing segment {i+1}: {result.stderr}")
                    # 删除可能创建的不完整文件
                    if os.path.exists(segment['output_file']):
                        os.remove(segment['output_file'])
                        
            except Exception as e:
                print(f"Exception processing segment {i+1}: {e}")
        
        if progress_callback:
            progress_callback(total_segments, total_segments, "Split complete")
        
        return successful_segments
    
    def get_video_thumbnail(self, video_path, time_seconds, output_path):
        """生成视频缩略图"""
        if not self.ffmpeg_available:
            return False
        
        # 优先使用本地ffmpeg
        current_dir = Path(__file__).parent
        ffmpeg_name, _ = self.get_ffmpeg_executable_names()
        local_ffmpeg = current_dir / ffmpeg_name
        
        if local_ffmpeg.exists():
            ffmpeg_cmd = str(local_ffmpeg)
        else:
            ffmpeg_cmd = 'ffmpeg'  # 使用系统PATH中的ffmpeg
        
        cmd = [
            ffmpeg_cmd, '-y',
            '-ss', str(time_seconds),
            '-i', video_path,
            '-vframes', '1',
            '-vf', 'scale=320:240',
            output_path
        ]
        
        try:
            result = subprocess.run(cmd, capture_output=True, text=True)
            return result.returncode == 0
        except Exception as e:
            print(f"Error generating thumbnail: {e}")
            return False
    
    def estimate_output_size(self, input_file, split_points, resolution=None):
        """估算输出文件大小"""
        video_info = VideoInfo(input_file)
        if not video_info.load_info():
            return None
        
        # 计算总时长
        times = [0] + sorted(split_points) + [video_info.duration]
        total_duration = sum(times[i+1] - times[i] for i in range(len(times)-1))
        
        # 估算比特率 - 固定为1080P 30fps高质量设置
        # 使用CRF 18的高质量编码，比特率会根据内容动态调整
        # 对于1080P 30fps，估算平均比特率为8-12 Mbps
        estimated_bitrate = 10000000  # 10 Mbps，适合1080P高质量视频
        
        # 计算文件大小 (字节)
        estimated_size = int(total_duration * estimated_bitrate / 8)
        
        return {
            'total_duration': total_duration,
            'estimated_bitrate': estimated_bitrate,
            'estimated_size_bytes': estimated_size,
            'estimated_size_mb': estimated_size / (1024 * 1024),
            'segment_count': len(times) - 1
        }


def format_file_size(size_bytes):
    """格式化文件大小"""
    if size_bytes < 1024:
        return f"{size_bytes} B"
    elif size_bytes < 1024 * 1024:
        return f"{size_bytes / 1024:.1f} KB"
    elif size_bytes < 1024 * 1024 * 1024:
        return f"{size_bytes / (1024 * 1024):.1f} MB"
    else:
        return f"{size_bytes / (1024 * 1024 * 1024):.1f} GB"


def format_duration(seconds):
    """格式化时长"""
    hours = int(seconds // 3600)
    minutes = int((seconds % 3600) // 60)
    secs = int(seconds % 60)
    
    if hours > 0:
        return f"{hours:02d}:{minutes:02d}:{secs:02d}"
    else:
        return f"{minutes:02d}:{secs:02d}"


def validate_split_points(split_points, duration):
    """验证拆分点"""
    if not split_points:
        return False, "至少需要一个拆分点"
    
    # 检查拆分点是否在有效范围内
    for point in split_points:
        if point <= 0 or point >= duration:
            return False, f"拆分点 {format_duration(point)} 超出视频范围"
    
    # 检查拆分点是否重复
    sorted_points = sorted(split_points)
    for i in range(len(sorted_points) - 1):
        if abs(sorted_points[i+1] - sorted_points[i]) < 1:
            return False, "拆分点间隔太近（小于1秒）"
    
    return True, "拆分点验证通过"